Marks

Marks are the building blocks of Plot charts.

The following chart, taken from the Cell Mark notebook, shows the rating of every episode of The Simpsons.

import polars as pl
from pyobsplot import Obsplot, Plot, d3, Math, js

simpsons = pl.read_csv("data/simpsons.csv")

Obsplot(
    {
        "height": 640,
        "padding": 0.05,
        "grid": True,
        "x": {"axis": "top", "label": "Season"},
        "y": {"label": "Episode"},
        "color": {"type": "linear", "scheme": "PiYG"},
        "marks": [
            Plot.cell(
                simpsons,
                {"x": "season", "y": "number_in_season", "fill": "imdb_rating"},
            ),
            Plot.text(
                simpsons,
                {
                    "x": "season",
                    "y": "number_in_season",
                    "text": "imdb_rating",
                    "title": "title",
                },
            ),
        ],
    }
)

Faceting allows to easily produce multiple plots by partitioning data. The following facet plot is taken from the Facets notebook.

penguins = pl.read_csv("data/penguins.csv")

Obsplot(
    {
        "height": 600,
        "grid": True,
        "facet": {"marginRight": 80},
        "marks": [
            Plot.frame({"facet": False}),
            Plot.dot(
                penguins,
                {
                    "x": "culmen_depth_mm",
                    "y": "culmen_length_mm",
                    "r": 1.5,
                    "fill": "#ccc",
                    "fx": "sex",
                    "fy": "species",
                    "facet": "exclude",
                },
            ),
            Plot.dot(
                penguins,
                {
                    "x": "culmen_depth_mm",
                    "y": "culmen_length_mm",
                    "fx": "sex",
                    "fy": "species",
                },
            ),
        ],
    }
)

Some marks allow for nice representation of complex data. The following plot, taken from the Arrow mark notebook, shows the evolution of inequality and population in various U.S. cities.

metros = pl.read_csv("data/metros.csv")

Obsplot(
    {
        "height": 600,
        "grid": True,
        "inset": 10,
        "x": {"type": "log", "label": "Population →"},
        "y": {"label": "↑ Inequality", "ticks": 4},
        "color": {
            "type": "diverging",
            "scheme": "burd",
            "label": "Change in inequality from 1980 to 2015",
            "legend": True,
            "ticks": 6,
            "tickFormat": "+f",
        },
        "marks": [
            Plot.arrow(
                metros,
                {
                    "x1": "POP_1980",
                    "y1": "R90_10_1980",
                    "x2": "POP_2015",
                    "y2": "R90_10_2015",
                    "bend": True,
                    "stroke": js("d => d.R90_10_2015 - d.R90_10_1980"),
                },
            ),
            Plot.text(
                metros,
                {
                    "x": "POP_2015",
                    "y": "R90_10_2015",
                    "filter": "highlight",
                    "text": "nyt_display",
                    "fill": "currentColor",
                    "stroke": "white",
                    "dy": -6,
                },
            ),
        ],
    }
)

The contour mark allows for nice representations of spatial data. The following example taken from the Contour mark notebook shows water vapor data from november 2022 (note that data processing and plot code are slightly modified to adapt to pyobsplot specificities).

vapor = (
    pl.read_csv("data/vapor.csv", has_header=False, null_values="99999.0")
    .transpose()
    .melt(variable_name="column", value_name="values")
)

Obsplot(
    {
        "projection": "equal-earth",
        "color": {
            "scheme": "blues",
            "legend": True,
            "ticks": 6,
            "nice": True,
            "label": "Water vapor (cm)",
        },
        "marks": [
            Plot.contour(
                vapor,
                {
                    "fill": "values",
                    "width": 360,
                    "height": 180,
                    "x1": -180,
                    "y1": 90,
                    "x2": 180,
                    "y2": -90,
                    "interval": 0.25,
                    "blur": 0.5,
                    "interpolate": "barycentric",
                    "stroke": "currentColor",
                    "strokeWidth": 0.5,
                    "clip": "sphere",
                },
            ),
            Plot.sphere(),
        ],
    }
)